package cn.com.lsy.product.lepao.util.payUtil.aliPayUtil;

import cn.com.lsy.product.lepao.common.AlipayConfig;
import cn.com.lsy.product.lepao.common.Constant;
import cn.com.lsy.product.lepao.util.CommonFunctionUtil;
import cn.com.lsy.product.lepao.util.payUtil.weChatPayUtil.SignUtils;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayFundAuthOperationDetailQueryModel;
import com.alipay.api.domain.AlipayFundAuthOrderAppFreezeModel;
import com.alipay.api.domain.AlipayFundAuthOrderUnfreezeModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundAuthOperationDetailQueryRequest;
import com.alipay.api.request.AlipayFundAuthOrderAppFreezeRequest;
import com.alipay.api.request.AlipayFundAuthOrderUnfreezeRequest;
import com.alipay.api.response.AlipayFundAuthOperationDetailQueryResponse;
import com.alipay.api.response.AlipayFundAuthOrderAppFreezeResponse;
import com.alipay.api.response.AlipayFundAuthOrderUnfreezeResponse;
import net.sf.json.JSONObject;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;


public class AlipayUtil {


    public static String getPayString(BigDecimal total_amount, String subject, String body, String orderNumber) {
        boolean rsa2 = true;
        Map<String, String> params = buildOrderParamMap(AlipayConfig.appId, rsa2, total_amount, subject, body, orderNumber);
        String orderParam = buildOrderParam(params);
        System.out.println("支付宝签名" + orderParam);
        String privateKey = AlipayConfig.privateKey;
        String sign = getSign(params, privateKey, rsa2);
        final String orderInfo = orderParam + "&" + sign;
        return orderInfo;
    }

    /**
     * 对支付参数信息进行签名
     *
     * @param map 待签名授权信息
     * @return
     */
    public static String getSign(Map<String, String> map, String rsaKey, boolean rsa2) {
        List<String> keys = new ArrayList<String>(map.keySet());
        // key排序
        Collections.sort(keys);

        StringBuilder authInfo = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = map.get(key);
            authInfo.append(buildKeyValue(key, value, false));
            authInfo.append("&");
        }

        String tailKey = keys.get(keys.size() - 1);
        String tailValue = map.get(tailKey);
        authInfo.append(buildKeyValue(tailKey, tailValue, false));

        String oriSign = SignUtils.sign(authInfo.toString(), rsaKey, rsa2);
        String encodedSign = "";

        try {
            encodedSign = URLEncoder.encode(oriSign, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "sign=" + encodedSign;
    }

    /**
     * 构造支付订单参数列表
     *
     * @param app_id
     * @return
     */
    public static Map<String, String> buildOrderParamMap(String app_id, boolean rsa2, BigDecimal total_amount, String subject, String body, String number) {
        Map<String, String> keyValues = new HashMap<String, String>();

        keyValues.put("app_id", app_id);

        keyValues.put("biz_content", "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\"" + total_amount + "\",\"subject\":\"" + subject + "\",\"body\":\"" + body + "\",\"out_trade_no\":\"" + number + "\"}");

        keyValues.put("charset", "utf-8");

        keyValues.put("method", "alipay.trade.app.pay");

        keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA");

        Date dt = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Long time = dt.getTime();
        System.err.println(simpleDateFormat.format(time));

        keyValues.put("timestamp", simpleDateFormat.format(time));

        keyValues.put("version", "1.0");

        //获取返回信息路径
        keyValues.put("notify_url", AlipayConfig.notifyUrl);
        System.err.println(keyValues.toString());
        return keyValues;
    }

    /**
     * 构造支付订单参数信息
     *
     * @param map 支付订单参数
     * @return
     */
    public static String buildOrderParam(Map<String, String> map) {
        List<String> keys = new ArrayList<String>(map.keySet());

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = map.get(key);
            sb.append(buildKeyValue(key, value, true));
            sb.append("&");
        }

        String tailKey = keys.get(keys.size() - 1);
        String tailValue = map.get(tailKey);
        sb.append(buildKeyValue(tailKey, tailValue, true));

        return sb.toString();
    }

    /**
     * 拼接键值对
     *
     * @param key
     * @param value
     * @param isEncode
     * @return
     */
    private static String buildKeyValue(String key, String value, boolean isEncode) {
        StringBuilder sb = new StringBuilder();
        sb.append(key);
        sb.append("=");
        if (isEncode) {
            try {
                sb.append(URLEncoder.encode(value, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                sb.append(value);
            }
        } else {
            sb.append(value);
        }
        return sb.toString();
    }

    /**
     * 支付签名
     *
     * @param orderSn
     * @param price
     * @return
     */
    public static String getSign(String orderSn, BigDecimal price, String title) {

        String sign = "";

        //封装签名参数
        Map<String, String> alipayParam = new HashMap<String, String>();
        alipayParam.put("sign_type", "RSA2");
        alipayParam.put("app_id", AlipayConfig.appId);
        alipayParam.put("method", "alipay.trade.app.pay");
        alipayParam.put("charset", "utf-8");
        alipayParam.put("timestamp", CommonFunctionUtil.getStringTime(Constant.formatType.second));
        alipayParam.put("version", "1.0");
        alipayParam.put("notify_url", AlipayConfig.notifyUrl);

        //业务参数
        Map<String, String> bizContent = new HashMap<String, String>();
        bizContent.put("body", title);
        bizContent.put("subject", title);
        bizContent.put("out_trade_no", orderSn);
        bizContent.put("total_amount", String.valueOf(price));
        bizContent.put("product_code", "QUICK_MSECURITY_PAY");
        JSONObject json = JSONObject.fromObject(bizContent);
        System.err.println(json);
        alipayParam.put("biz_content", json.toString());

        try {
            sign = AlipaySignature.rsaSign(alipayParam, AlipayConfig.privateKey, "UTF-8");
            System.out.println(sign);

        } catch (AlipayApiException e) {
            e.printStackTrace();
            return sign;
        }
        return sign;
    }


    // 将request中的参数转换成Map
    public static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<String, String>();

        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();

        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;

            if (valLen == 1) {
                retMap.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }

        return retMap;
    }

    public static AliPayCallBackRet buildAlipayNotifyParam(Map<String, String> params) {
        String json = JSON.toJSONString(params);
        return JSON.parseObject(json, AliPayCallBackRet.class);
    }


    /**
     * 支付宝预授权接口
     *
     * @throws AlipayApiException
     */
    public static String selectZhimaCredit(String number, String amount) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
                AlipayConfig.appId, AlipayConfig.privateKey, "json", "utf-8", AlipayConfig.publicKey, "RSA2");
        AlipayFundAuthOrderAppFreezeRequest request = new AlipayFundAuthOrderAppFreezeRequest();
        AlipayFundAuthOrderAppFreezeModel model = new AlipayFundAuthOrderAppFreezeModel();
        model.setOrderTitle("支付宝预授权");
        model.setOutOrderNo(number);//替换为实际订单号
        model.setOutRequestNo(CommonFunctionUtil.createUuid());//替换为实际请求单号，保证每次请求都是唯一的
        model.setPayeeUserId(AlipayConfig.pid);//payee_user_id,Payee_logon_id不能同时为空
        //model.setPayeeLogonId("2088721566000627");
        model.setProductCode("PRE_AUTH_ONLINE");//PRE_AUTH_ONLINE为固定值，不要替换
        model.setAmount(amount);
        //需要支持信用授权，该字段必传
        Map<String, Object> ProductParamMap = new HashMap<String, Object>();
        ProductParamMap.put("category", "RENT_GYM_EQUIPMENT");
        ProductParamMap.put("outStoreAlias", "乐跑共享健身");
        ProductParamMap.put("outStoreCode", "charge001");
        model.setExtraParam(JSON.toJSONString(ProductParamMap));
        //选填字段，指定支付渠道
        //model.setEnablePayChannels("[{\"payChannelType\":\"PCREDIT_PAY\"},{\"payChannelType\":\"MONEY_FUND\"},{\"payChannelType\":\"CREDITZHIMA\"}]");
        request.setBizModel(model);
        request.setNotifyUrl(AlipayConfig.zhimaNotifyUrl);//异步通知地址，必填，该接口只通过该参数进行异步通知
        AlipayFundAuthOrderAppFreezeResponse response = alipayClient.sdkExecute(request);//注意这里是sdkExecute，可以获取签名参数
        if (response.isSuccess()) {
            return response.getBody();
        } else {
            return null;
        }
    }

    /**
     * 测试预授权解冻l
     */
    public static AlipayFundAuthOrderUnfreezeResponse fundAuthOrderUnFreeze(String authNo, String requestNo, String amount, String remark) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
                AlipayConfig.appId, AlipayConfig.privateKey, "json", "utf-8", AlipayConfig.publicKey, "RSA2");
        AlipayFundAuthOrderUnfreezeRequest request = new AlipayFundAuthOrderUnfreezeRequest();
        AlipayFundAuthOrderUnfreezeModel model = new AlipayFundAuthOrderUnfreezeModel();
        model.setAuthNo(authNo); // 支付宝资金授权订单号，在授权冻结成功时返回需要入库保存
        model.setOutRequestNo(requestNo);//同一商户每次不同的资金操作请求，商户请求流水号不能重复,且与冻结流水号不同
        model.setAmount(amount); // 本次操作解冻的金额，单位为：元（人民币），精确到小数点后两位
        model.setRemark(remark); // 商户对本次解冻操作的附言描述，长度不超过100个字母或50个汉字
        //选填字段，信用授权订单，针对信用全免订单，传入该值完结信用订单，形成芝麻履约记录
        model.setExtraParam("{\"unfreezeBizInfo\":\"{\\\"bizComplete\\\":\\\"true\\\"}\"}");
        request.setBizModel(model);
        request.setNotifyUrl(AlipayConfig.zhimaNotifyUrl);//异步通知地址，必填，该接口只通过该参数进行异步通知

        AlipayFundAuthOrderUnfreezeResponse response = alipayClient.execute(request);
        System.err.println("response: {}" + response.getBody());

        return response;
    }

    public static void fundAuthQuery() throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", AlipayConfig.appId, AlipayConfig.privateKey, "json", "utf-8", AlipayConfig.publicKey, "RSA2");
        AlipayFundAuthOperationDetailQueryRequest request = new AlipayFundAuthOperationDetailQueryRequest();
        AlipayFundAuthOperationDetailQueryModel model = new AlipayFundAuthOperationDetailQueryModel();
        //model.setAuthNo("2017120110002001390206804295"); // 支付宝资金授权订单号，在授权冻结成功时返回参数中获得
        model.setOutOrderNo(CommonFunctionUtil.createUuid()); //商户的授权资金订单号，与支付宝的授权资金订单号不能同时为空
        //model.setOperationId("20171201317348823902"); //支付宝的授权资金操作流水号，冻结成功同步返回
        //model.setOutRequestNo("requestNo000003");//商户的授权资金操作流水号，与支付宝的授权资金操作流水号不能同时为空，该值为冻结或解冻是的outRequestNo
        request.setBizModel(model);
        AlipayFundAuthOperationDetailQueryResponse response = alipayClient.execute(request);
        System.err.println(response.getBody());
    }
}
